<?php

/*
 * Copyright (C) 2009 - 2011 Pham Cong Dinh
 *
 * This file is part of Spica.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

/**
 * Set of methods for creating application structures in Spica.
 *
 * @category   spica
 * @package    tools
 * @subpackage cmd
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      August 09, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: _includes.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class ApplicationTools
{
    /**
     * Application name.
     *
     * @var string
     */
    public $app;

    /**
     * Theme name.
     *
     * @var string
     */
    public $theme;

    /**
     * Package name.
     *
     * @var string
     */
    public $package;

    /**
     * Bootstrap path.
     *
     * @var string
     */
    public $basePath;

    /**
     * Constructs an object of <code>ApplicationTools</code>.
     */
    public function __construct()
    {
        $this->basePath = dirname(dirname(__FILE__));
    }

    /**
     * Sets application name.
     *
     * @param string $name
     */
    public function setApplicationName($name)
    {
        $this->app = $name;
    }

    /**
     * Sets theme name.
     *
     * @param string $name
     */
    public function setThemeName($name)
    {
        $this->theme = $name;
    }

    /**
     * Sets package name.
     *
     * @param string $name
     */
    public function setPackageName($name)
    {
        $this->package = $name;
    }

    /**
     *
     * @param  string $basePath Path to /public/theme
     */
    public function createThemeStaticDirs()
    {
        /**
         * Creates directory structure for theme-specific static files.
         */
        $dirs = array(
          'css',
          'js',
          'flash',
          'image',
        );

        $path     = $this->basePath.'/public/theme/'.$this->app;

        if (false === file_exists($path))
        {
            mkdir($path, 0770, true);
        }

        chdir($path);

        echo "Create theme directory for static file: ";
        if (false === file_exists($this->theme))
        {
            mkdir($this->theme);
            echo "Created. ".PHP_EOL;
        }
        else
        {
            echo "Existed. Skipped. ".PHP_EOL;
        }

        chdir($this->theme);
        $this->_createDirectories($dirs);

        if (false === file_exists($path.'/'.$this->theme.'/css/reset.css'))
        {
            if (false === copy($this->basePath.'/tools/cmd/css/reset.css', $path.'/'.$this->theme.'/css/reset.css'))
            {
                echo sprintf("Unable to create %s file. ", $path.'/'.$this->theme.'/css/reset.css').PHP_EOL;
            }
        }

        if (false === file_exists($path.'/'.$this->theme.'/css/global.css'))
        {
            if (false === copy($this->basePath.'/tools/cmd/css/global.css', $path.'/'.$this->theme.'/css/global.css'))
            {
                echo sprintf("Unable to create %s file. ", $path.'/'.$this->theme.'/css/global.css').PHP_EOL;
            }
        }
    }

    public function createThemeAppDirs()
    {
        /**
         * Creates theme directory structure.
         */
        $dirs = array(
          'block',
          'blockgroup',
          'css',
          'js',
          'meta',
          'layout',
          'page',
          'partial',
          'ui',
        );

        $appPath = $this->basePath.'/apps/'.$this->app;

        if (false === file_exists($appPath))
        {
            exit('Application named "'.$this->app.'" has not been existed yet.'.PHP_EOL);
        }

        chdir($appPath.'/view/theme');

        echo "Create application theme directory: ";
        if (false === file_exists($this->theme))
        {
            mkdir($this->theme);
            echo "Created. ".PHP_EOL;
        }
        else
        {
            echo "Existed. Skipped. ".PHP_EOL;
        }

        chdir($this->theme);
        $this->_createDirectories($dirs);

        echo "Create theme sample layout page: ";

        if (false === file_exists('index.tpl.php'))
        {
            copy($this->basePath.'/tools/cmd/theme/index.tpl.php', $appPath.'/view/theme/'.$this->theme.'/layout/index.tpl.php');
            $content = file_get_contents($appPath.'/view/theme/'.$this->theme.'/layout/index.tpl.php');
            file_put_contents($appPath.'/view/theme/'.$this->theme.'/layout/index.tpl.php', str_replace(array('{appName}', '{themeName}'), array($this->app, $this->theme), $content));
        }
    }

    /**
     * Creates application directory structure.
     */
    public function createAppDirs()
    {
        $dirs = array(
          'block',
          'blockgroup',
          'config',
          'controller',
          'event',
          'exception',
          'filter',
          'form',
          'helper',
          'lib',
          'locale',
          'model',
          'security',
          'service',
          'session',
          'view',
          'ui',
        );

        chdir($this->basePath.'/apps');

        echo "Create application directory: ";
        if (true === file_exists($this->app))
        {
            echo "Existed. Skipped. ".PHP_EOL;
        }
        elseif (false === mkdir($this->app))
        {
            exit("Failed. ".PHP_EOL);
        }
        else
        {
            echo "Created. ".PHP_EOL;
        }

        chdir($this->app);
        $this->_createDirectories($dirs);

        $appPath = $this->basePath.'/apps/'.$this->app;
        // Copy config files
        if (false === copy($this->basePath.'/tools/cmd/config/context.php', $appPath.'/config/context.php'))
        {
            echo "Unable to create config/context.php file. ".PHP_EOL;
        }
        else
        {
            $content = file_get_contents($appPath.'/config/context.php');
            $content = str_replace('SpicaContext::switchProfile(\'app0\')', 'SpicaContext::switchProfile(\'app1\')', $content);
            file_put_contents($appPath.'/config/context.php', $content);
        }

        if (false === copy($this->basePath.'/tools/cmd/config/exception.php', $appPath.'/config/exception.php'))
        {
            echo "Unable to create config/exception.php file. ".PHP_EOL;
        }

        if (false === copy($this->basePath.'/tools/cmd/config/global.php', $appPath.'/config/global.php'))
        {
            echo "Unable to create config/global.php file. ".PHP_EOL;
        }
        else
        {
            $callback = new GlobalThemeCallback();
            $callback->theme = $this->theme;
            FileLineUtils::replaceLineByCallback($appPath.'/config/global.php', 88, $callback);

            $callback = new GlobalPackageCallback();
            $callback->package = $this->package;
            FileLineUtils::replaceLineByCallback($appPath.'/config/global.php', 83, $callback);
        }

        // Creates sample controller
        echo "Create controller directory structure: ";
        if (true === file_exists($appPath.'/controller/'.$this->package.'/home'))
        {
            echo "Existed. Skipped ".PHP_EOL;
        }
        elseif (false === mkdir($appPath.'/controller/'.$this->package.'/home', 0750, true))
        {
            echo "Unable to create $appPath/controller/$this->package/home directory. ".PHP_EOL;
        }
        else
        {
            echo "Created. ".PHP_EOL;
        }

        $controllerClass = ucfirst($this->package).'_HomeIndex';
        echo "Create sample controller class controller/$this->package/home/$controllerClass.php: ";

        if (true === file_exists($appPath."/controller/$this->package/home/$controllerClass.php"))
        {
            echo "Existed. Skipped ".PHP_EOL;
        }
        elseif (false === copy($this->basePath.'/tools/cmd/controller/Base_HomeIndex.php', $appPath."/controller/$this->package/home/$controllerClass.php"))
        {
            echo "Unable to create controller/$this->package/home/$controllerClass.php file. ".PHP_EOL;
        }
        else
        {
            $content = file_get_contents($appPath."/controller/$this->package/home/$controllerClass.php");
            $content = str_replace('Base_HomeIndex', $controllerClass, $content);
            $content = str_replace('{date}', date('F d, Y'), $content);
            $content = file_put_contents($appPath."/controller/$this->package/home/$controllerClass.php", $content);
            echo "Content populated ".PHP_EOL;
        }

        echo "Create view/filter: ";
        if (true === file_exists($appPath.'/view/filter'))
        {
            echo "Existed. Skipped ".PHP_EOL;
        }
        else
        {
            mkdir($appPath.'/view/filter', 0750, true);
            echo "Created. ".PHP_EOL;
        }

        echo "Create view/helper: ";
        if (true === file_exists($appPath.'/view/helper'))
        {
            echo "Existed. Skipped ".PHP_EOL;
        }
        else
        {
            mkdir($appPath.'/view/helper', 0750, true);
            echo "Created. ".PHP_EOL;
        }

        echo "Create view/theme: ";
        if (true === file_exists($appPath.'/view/theme'))
        {
            echo "Existed. Skipped ".PHP_EOL;
        }
        else
        {
            mkdir($appPath.'/view/theme', 0750, true);
            echo "Created. ".PHP_EOL;
        }
    }

    /**
     * Creates list of directories.
     *
     * @param array $dirs
     */
    protected function _createDirectories(array $dirs)
    {
        foreach ($dirs as $dir)
        {
            echo "Create directory \"$dir\": ";

            if (false === file_exists($dir))
            {
                mkdir($dir);
                echo "Created. ".PHP_EOL;
            }
            else
            {
                echo "Existed. Skipped. ".PHP_EOL;
            }
        }
    }
}

class GlobalThemeCallback implements FileLineUtilCallback
{
    public $theme;

    public function process($oldContent)
    {
        return str_replace("'default'", "'{$this->theme}'", $oldContent);
    }
}

class GlobalPackageCallback implements FileLineUtilCallback
{
    public $package;

    public function process($oldContent)
    {
        return str_replace("'base'", "'{$this->package}'", $oldContent);
    }
}

class FileLineUtils
{
    /**
     * Replaces a line content with new one in a text file.
     *
     * @param  string $fileName
     * @param  string $oldLine
     * @param  string $newLine
     */
    public static function replaceLine($fileName, $oldLine, $newLine)
    {
        $lines = file($fileName);

        for ($i = 0; $i < count($lines); ++$i)
        {
            if ($lines[$i] == $oldLine)
            {
                $lines[$i] = $newLine;
            }
        }

        $f = fopen($fileName, 'w');
        fwrite($f, implode('', $lines));
        fclose($f);
    }

    /**
     * Replaces a line content with new one in a text file, using a callback.
     *
     * @param string $fileName
     * @param int $lineNumber
     */
    public static function replaceLineByCallback($fileName, $lineNumber, FileLineUtilCallback $callback)
    {
        $lines = file($fileName);
        $old   = $lines[$lineNumber];
        $lines[$lineNumber] = $callback->process($old);
        $f = fopen($fileName, 'w');
        fwrite($f, implode('', $lines));
        fclose($f);
    }
}

interface FileLineUtilCallback
{
    public function process($oldContent);
}

?>